package com.rtsapp.agent.handler;

import com.rtsapp.agent.rules.AgentUtils;
import com.rtsapp.server.logger.Logger;
import com.rtsapp.server.logger.LoggerFactory;

import java.io.File;
import java.lang.instrument.Instrumentation;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * Created by liwang on 17-3-16.
 */
public class HotfixHandler {
    private final static Logger LOGGER = LoggerFactory.getLogger( HotfixHandler.class );

    // hotfix执行, 具体的逻辑就在这里
    private HotfixExecutor hotFixExecutor = null;

    // hotfix定时任务
    private ScheduledFuture hotFixTimeTask = null;
    // 定时任务执行的次数
    private long taskRunTimes = 0;
    // hotfix 自动修复任务使用的规则
    private String[] autoRules = null;

    /**
     * 初始化热更新所需的文件夹
     */
    private void initHotFilesDir( ) {
        // 1. 删除原目录
        FileUtil.deleteAllFilesOfDir( new File( HotfixExecutor.ROOT_PATH ) );
        // 2. 重新创建文件存放目录
        new File( HotfixExecutor.FIXED_PATH ).mkdirs( );
        new File( HotfixExecutor.USELESS_PATH ).mkdirs( );
    }

    /**
     * @param inst
     * @return init是否成功
     */
    public boolean initialize( Instrumentation inst ) {

        if ( inst == null ) {
            LOGGER.error( "rts-hotfix:  HotfixHandler.initialize( Instrumentation inst ):  Instrumentation为null! 请检查agentLoad部分代码!" );
            return false;
        }

        if ( !inst.isRedefineClassesSupported( ) ) {
            LOGGER.error( "rts-hotfix:  当前运行环境不支持 RedefineClasses, 将无法热更新任何代码!" );
            return false;
        }

        initHotFilesDir( );

        if ( isHotFixReady( ) ) {
            return true;
        }


        hotFixExecutor = new HotfixExecutor( inst );

        return true;
    }

    public boolean isHotFixReady( ) {
        return this.hotFixExecutor != null;
    }

    /**
     * 手动执行一次热更新
     */
    public boolean runHotFixOnce( String[] rules ) {
        LOGGER.info( "hotfix:  手动执行一次热修复" );
        hotFixExecutor.startHotFix( rules );
        return true;
    }


    private final Object timeTaskLock = new Object( );

    /**
     * 设置热更新的定时任务
     *
     * @param period
     */
    public boolean setHotFixTimeTask( int period, String[] rules ) {

        if ( isHotFixTaskValid( ) ) {
            return false;
        }

        if ( period <= 0 ) {
            LOGGER.error( "rts-hotfix:  定时任务的时间间隔必须大于0!" );
            return false;
        }

        synchronized ( timeTaskLock ) {

            if ( isHotFixTaskValid( ) ) {
                return false;
            }

            // 设置新的自动修复规则
            if ( AgentUtils.isEmpty( this.autoRules = rules ) ) {
                LOGGER.error( "rts-hotfix:  自动修复任务没有设置规则! 定时任务终止启动!" );
                return false;
            }

            // 设置定时任务
            hotFixTimeTask = Executors.newScheduledThreadPool( 1 ).scheduleAtFixedRate(
                    new Runnable( ) {
                        @Override
                        public void run( ) {
                            LOGGER.debug( "rts-hotfix:  自动修复任务: 第 {} 次运行 !!", ++taskRunTimes );
                            hotFixExecutor.startHotFix( autoRules );
                        }
                    },
                    period,
                    period,
                    TimeUnit.SECONDS );


            LOGGER.info( "rts-hotfix:  自动修复任务已经启动 ..." );

        }

        return true;
    }


    /**
     * 判断定时任务是否还有效
     *
     * @return
     */
    private boolean isHotFixTaskValid( ) {
        return hotFixTimeTask != null && !hotFixTimeTask.isCancelled( ) && !hotFixTimeTask.isDone( );
    }

    /**
     * 停止定时任务的运行
     *
     * @param mayInterruptIfRunning
     */
    public void cancelHotFixTimeTask( boolean mayInterruptIfRunning ) {
        if ( isHotFixTaskValid( ) ) {
            hotFixTimeTask.cancel( mayInterruptIfRunning );
        }
        hotFixTimeTask = null;
        LOGGER.info( "hotfix:  热修复定时任务已经取消!" );
    }


}
